/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package players;

import data.Line;
import interfaces.GameState;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Marcel
 */
public class Minimax extends AbstractPlayer{

    private static final int INF = Integer.MAX_VALUE;
    private static int DEPTH = 0;
    private boolean isPlayer1 = false;
    

    @Override
    public Line makeMove(GameState gs) {
        List<Line> lines = gs.getRemainingLines();
        if (lines.size() > 30) DEPTH = 2;
        else if (lines.size() > 20) DEPTH = 3;
        else if (lines.size() > 15) DEPTH = 5;
        else DEPTH = 6;
        return minimaxDecision(gs);
    }
    
    private Line max (List<Tuple<Integer, Line>> l) {
        Integer m = new Integer(-INF);
        List<Tuple<Integer, Line>> r = new ArrayList<>();
        for (Tuple<Integer, Line> entry : l)
        {
            m = Math.max(m,entry.getT());
        }
        for (Tuple<Integer, Line> entry : l) {
            if (entry.getT() == m) {
                r.add(entry);
            }
        }
        return r.get((int)(Math.random()*r.size())).getU();
    }
    
    private Line min (List<Tuple<Integer, Line>> l) {
        Integer m = new Integer(-INF);
        List<Tuple<Integer, Line>> r = new ArrayList<>();
        for (Tuple<Integer, Line> entry : l)
        {
            m = Math.min(m,entry.getT());
        }
        for (Tuple<Integer, Line> entry : l) {
            if (entry.getT() == m) {
                r.add(entry);
            }
        }
        return r.get((int)(Math.random()*r.size())).getU();
    }
    
    
    
    private Line minimaxDecision(GameState state) {
        List<Line> lines = state.getRemainingLines();
        List<Tuple<Integer, Line>> m = new ArrayList<>();
        //System.out.println("Início");
        int minMaxv;
        int value;
        this.isPlayer1 = (state.getPlayer() == 1);
        for (Line line : lines) {
            GameState clone = state.clone();
            value = clone.addLine(line);
            if(value  == 0 ){
                minMaxv = minValue(-1,clone);
            }else{
                minMaxv = maxValue(-1,clone);
            }
            m.add( new Tuple(minMaxv,line));
            //System.out.println(minMaxv+" ("+line.ax+","+line.ay+")("
            //        +line.bx+","+line.by+")");
        }
        return max(m);
    }
    
    private int maxValue(int k, GameState state) {
        List<Line> lines = state.getRemainingLines();
        if(k == DEPTH || lines.isEmpty()){
            return state.getValue()*((this.isPlayer1)?1:-1);
        }
        int max = -INF, value;
        for(Line line : lines){
            GameState clone = state.clone();
            value = clone.addLine(line);
            if(value < 1){
                max = Math.max(max, minValue(k+1, clone));
            }else{
                max = Math.max(max, maxValue(k+1, clone));
            }
        }
        return max;
    }
    
    private int minValue(int k,GameState state) {
        List<Line> lines = state.getRemainingLines();
        if(k == DEPTH || lines.isEmpty()){
            return state.getValue()*((this.isPlayer1)?1:-1);
        }
        int min = INF, value;
        for(Line line : lines){
            GameState clone = state.clone();
            value = clone.addLine(line);
            if(value < 1){
                min = Math.min(min, maxValue(k+1, clone));
            }else{
                min = Math.min(min, minValue(k+1, clone));
            }
        }
        return min;
    }
    
//    function MINIMAX-DECISION(estado) retorna uma ação
//        return arg max a in ACTIONS ( s) MIN-VALUE(RESULT(state, a))
//    ______________________________________________________________
//    function MAX-VALUE( estado) retorna um valor de utilidade
//        if TERMINAL-TEST(estado) then return UTILITY(estado)
//            v = - 00
//        for each a in ACTIONS(estado) do
//            v <- MAX(v, MIN-VALUE(RESULT(s, a)))
//        return v
//    ______________________________________________________________
//    function MIN-VALUE( estado) retorna um valor de utilidade
//        if TERMINAL-TEST(estado) then return UTILITY(estado)
//            v = 00
//        for each a in ACTIONS(estado) do
//            v <- MIN(v, MAX-VALUE(RESULT(s, a)))
//        return v

    @Override
    public String getName() {
        return "Minimax";
    }
    
}
